/*
 * @file main.cpp
 * @author zhangpeihao
 */

#include <gtest/gtest.h>
#include <list>
#include <algorithm>
#include "utcase.h"
#include <zsystem/core/xml/xmlConfig.h>

using namespace std;

#define TEST_parse                0
#define TEST_xmlbase              0
#define TEST_xmlFile              0
#define TEST_getOpt               0
#define TEST_xmlConfig            0
#define TEST_saxParse             0
#define TEST_objParse             1

#if TEST_parse

TEST_F(utcase, parse)
{
  Z_I8 i8(0);
  EXPECT_TRUE(zsystem::xmlbase::parseSigned("0", i8));
  EXPECT_EQ(0, (Z_I32)i8);
  EXPECT_TRUE(zsystem::xmlbase::parseSigned("1", i8));
  EXPECT_EQ(1, (Z_I32)i8);
  EXPECT_TRUE(zsystem::xmlbase::parseSigned("127", i8));
  EXPECT_EQ(127, (Z_I32)i8);
  EXPECT_TRUE(zsystem::xmlbase::parseSigned("-1", i8));
  EXPECT_EQ(-1, (Z_I32)i8);
  EXPECT_TRUE(zsystem::xmlbase::parseSigned("-128", i8));
  EXPECT_EQ(-128, (Z_I32)i8);
  EXPECT_FALSE(zsystem::xmlbase::parseSigned("128", i8));
  EXPECT_FALSE(zsystem::xmlbase::parseSigned("-129", i8));

  Z_I16 i16(0);
  EXPECT_TRUE(zsystem::xmlbase::parseSigned("0", i16));
  EXPECT_EQ(0, i16);
  EXPECT_TRUE(zsystem::xmlbase::parseSigned("1", i16));
  EXPECT_EQ(1, i16);
  EXPECT_TRUE(zsystem::xmlbase::parseSigned("32767", i16));
  EXPECT_EQ(32767, i16);
  EXPECT_TRUE(zsystem::xmlbase::parseSigned("-1", i16));
  EXPECT_EQ(-1, i16);
  EXPECT_TRUE(zsystem::xmlbase::parseSigned("-32768", i16));
  EXPECT_EQ(-32768, i16);
  EXPECT_FALSE(zsystem::xmlbase::parseSigned("32768", i16));
  EXPECT_FALSE(zsystem::xmlbase::parseSigned("-32769", i16));

  Z_I32 i32(0);
  EXPECT_TRUE(zsystem::xmlbase::parseSigned("0", i32));
  EXPECT_EQ(0, i32);
  EXPECT_TRUE(zsystem::xmlbase::parseSigned("1", i32));
  EXPECT_EQ(1, i32);
  EXPECT_TRUE(zsystem::xmlbase::parseSigned("2147483647", i32));
  EXPECT_EQ(2147483647, i32);
  EXPECT_TRUE(zsystem::xmlbase::parseSigned("-1", i32));
  EXPECT_EQ(-1, i32);
  EXPECT_TRUE(zsystem::xmlbase::parseSigned("-2147483648", i32));
  EXPECT_EQ(-2147483648, i32);
  EXPECT_FALSE(zsystem::xmlbase::parseSigned("2147483648", i32));
  EXPECT_FALSE(zsystem::xmlbase::parseSigned("-2147483649", i32));

  Z_I64 i64(0);
  EXPECT_TRUE(zsystem::xmlbase::parseSigned("0", i64));
  EXPECT_EQ(0LL, i64);
  EXPECT_TRUE(zsystem::xmlbase::parseSigned("1", i64));
  EXPECT_EQ(1LL, i64);
  EXPECT_TRUE(zsystem::xmlbase::parseSigned("9223372036854775807", i64));
  EXPECT_EQ(9223372036854775807LL, i64);
  EXPECT_TRUE(zsystem::xmlbase::parseSigned("-1", i64));
  EXPECT_EQ(-1LL, i64);
  EXPECT_TRUE(zsystem::xmlbase::parseSigned("-9223372036854775808", i64));
  EXPECT_EQ(-9223372036854775808LL, i64);
  EXPECT_FALSE(zsystem::xmlbase::parseSigned("9223372036854775808", i64));
  EXPECT_FALSE(zsystem::xmlbase::parseSigned("-9223372036854775809", i64));

  Z_U8 u8(0);
  EXPECT_TRUE(zsystem::xmlbase::parseUnsigned("0", u8));
  EXPECT_EQ(0, (Z_U32)u8);
  EXPECT_TRUE(zsystem::xmlbase::parseUnsigned("1", u8));
  EXPECT_EQ(1, (Z_U32)u8);
  EXPECT_TRUE(zsystem::xmlbase::parseUnsigned("255", u8));
  EXPECT_EQ(255, (Z_U32)u8);
  EXPECT_FALSE(zsystem::xmlbase::parseUnsigned("256", u8));
  EXPECT_FALSE(zsystem::xmlbase::parseUnsigned("-1", u8));

  Z_U16 u16(0);
  EXPECT_TRUE(zsystem::xmlbase::parseUnsigned("0", u16));
  EXPECT_EQ(0, u16);
  EXPECT_TRUE(zsystem::xmlbase::parseUnsigned("1", u16));
  EXPECT_EQ(1, u16);
  EXPECT_TRUE(zsystem::xmlbase::parseUnsigned("65535", u16));
  EXPECT_EQ(65535, u16);
  EXPECT_FALSE(zsystem::xmlbase::parseUnsigned("65536", u16));
  EXPECT_FALSE(zsystem::xmlbase::parseUnsigned("-1", u16));

  Z_U32 u32(0);
  EXPECT_TRUE(zsystem::xmlbase::parseUnsigned("0", u32));
  EXPECT_EQ(0, u32);
  EXPECT_TRUE(zsystem::xmlbase::parseUnsigned("1", u32));
  EXPECT_EQ(1, u32);
  EXPECT_TRUE(zsystem::xmlbase::parseUnsigned("4294967295", u32));
  EXPECT_EQ(4294967295, u32);
  EXPECT_FALSE(zsystem::xmlbase::parseUnsigned("4294967296", u32));
  EXPECT_FALSE(zsystem::xmlbase::parseUnsigned("-1", u32));

  Z_U64 u64(0);
  EXPECT_TRUE(zsystem::xmlbase::parseUnsigned("0", u64));
  EXPECT_EQ(0ULL, u64);
  EXPECT_TRUE(zsystem::xmlbase::parseUnsigned("1", u64));
  EXPECT_EQ(1ULL, u64);
  EXPECT_TRUE(zsystem::xmlbase::parseUnsigned("18446744073709551615", u64));
  EXPECT_EQ(18446744073709551615ULL, u64);
  EXPECT_FALSE(zsystem::xmlbase::parseUnsigned("18446744073709551616", u64));
  EXPECT_FALSE(zsystem::xmlbase::parseUnsigned("-1", u64));

  Z_FLOAT f(0);
  EXPECT_TRUE(zsystem::xmlbase::parseFloat("0", f));
  EXPECT_FLOAT_EQ(0.0f, f);
  EXPECT_TRUE(zsystem::xmlbase::parseFloat("1", f));
  EXPECT_FLOAT_EQ(1.0f, f);
  EXPECT_TRUE(zsystem::xmlbase::parseFloat("0.123456", f));
  EXPECT_FLOAT_EQ(0.123456f, f);
  EXPECT_TRUE(zsystem::xmlbase::parseFloat("123456", f));
  EXPECT_FLOAT_EQ(123456.0f, f);
  EXPECT_TRUE(zsystem::xmlbase::parseFloat("0.123456789", f));
  EXPECT_FLOAT_EQ(0.12345679f, f);
  EXPECT_TRUE(zsystem::xmlbase::parseFloat("123456789", f));
  EXPECT_FLOAT_EQ(123456790.0f, f);


  Z_DOUBLE d(0);
  EXPECT_TRUE(zsystem::xmlbase::parseFloat("0", d));
  EXPECT_DOUBLE_EQ(0.0l, d);
  EXPECT_TRUE(zsystem::xmlbase::parseFloat("1", d));
  EXPECT_DOUBLE_EQ(1.0l, d);
  EXPECT_TRUE(zsystem::xmlbase::parseFloat("0.123456", d));
  EXPECT_DOUBLE_EQ(0.123456l, d);
  EXPECT_TRUE(zsystem::xmlbase::parseFloat("123456", d));
  EXPECT_DOUBLE_EQ(123456.0l, d);
  EXPECT_TRUE(zsystem::xmlbase::parseFloat("0.123456789", d));
  EXPECT_DOUBLE_EQ(0.123456789l, d);
  EXPECT_TRUE(zsystem::xmlbase::parseFloat("123456789", d));
  EXPECT_DOUBLE_EQ(123456789.0l, d);

}
#endif

#if TEST_xmlbase

TEST_F(utcase, xmlbase)
{
  zsystem::xmlNode root;
  EXPECT_TRUE(xmlbase.getRootNode(root));
  EXPECT_TRUE(root != Z_NULL);
  EXPECT_EQ((Z_U32)TiXmlNode::TINYXML_ELEMENT, (Z_U32)root->Type());
  EXPECT_STREQ("ToDo", root->Value());

  zsystem::xmlNode strNode(Z_NULL);
  EXPECT_TRUE(xmlbase.getChildNode(root, "String", strNode));
  EXPECT_TRUE(strNode != Z_NULL);
  EXPECT_STREQ("String", strNode->Value());

  const char* string(Z_NULL);
  std::string stdString;

  do{
    EXPECT_TRUE(xmlbase.read<const char*>(strNode, string));
    EXPECT_TRUE(xmlbase.read<std::string>(strNode, stdString));
    strNode = xmlbase.getNextSibling(strNode, "String");
  } while(strNode != Z_NULL);

  EXPECT_TRUE(xmlbase.getChildNode(root, "StringERR", strNode));
  EXPECT_TRUE(strNode != Z_NULL);
  EXPECT_STREQ("StringERR", strNode->Value());
  do{
    EXPECT_FALSE(xmlbase.read<const char*>(strNode, string));
    strNode = xmlbase.getNextSibling(strNode, "StringERR");
  } while(strNode != Z_NULL);

  zsystem::xmlNode u32Node(Z_NULL);
  EXPECT_TRUE(xmlbase.getChildNode(root, "U32", u32Node));
  EXPECT_TRUE(u32Node != Z_NULL);
  EXPECT_STREQ("U32", u32Node->Value());
  Z_U32 u32(0);
  EXPECT_TRUE(xmlbase.read<Z_U32>(u32Node, u32));
  EXPECT_EQ((Z_U32)0, u32);
  EXPECT_TRUE(xmlbase.getNextSibling(u32Node, "U32",u32Node));
  EXPECT_TRUE(xmlbase.read<Z_U32>(u32Node, u32));
  EXPECT_EQ((Z_U32)1, u32);
  EXPECT_TRUE(xmlbase.getNextSibling(u32Node, "U32",u32Node));
  EXPECT_TRUE(xmlbase.read<Z_U32>(u32Node, u32));
  EXPECT_EQ((Z_U32)4294967295, u32);
  EXPECT_FALSE(xmlbase.getNextSibling(u32Node, "U32",u32Node));

  u32Node = xmlbase.getChildNode(root, "U32ERR");
  EXPECT_TRUE(u32Node != Z_NULL);
  do{
    EXPECT_FALSE(xmlbase.read<Z_U32>(u32Node, u32));
    u32Node = xmlbase.getNextSibling(u32Node, "U32ERR");
  } while(u32Node != Z_NULL);

  zsystem::xmlNode i32Node(Z_NULL);
  EXPECT_TRUE(xmlbase.getChildNode(root, "I32", i32Node));
  EXPECT_TRUE(i32Node != Z_NULL);
  EXPECT_STREQ("I32", i32Node->Value());
  Z_I32 i32(0);
  EXPECT_TRUE(xmlbase.read<Z_I32>(i32Node, i32));
  EXPECT_EQ((Z_I32)0, i32);
  EXPECT_TRUE(xmlbase.getNextSibling(i32Node, "I32",i32Node));
  EXPECT_TRUE(xmlbase.read<Z_I32>(i32Node, i32));
  EXPECT_EQ((Z_I32)1, i32);
  EXPECT_TRUE(xmlbase.getNextSibling(i32Node, "I32",i32Node));
  EXPECT_TRUE(xmlbase.read<Z_I32>(i32Node, i32));
  EXPECT_EQ((Z_I32)-1, i32);
  EXPECT_TRUE(xmlbase.getNextSibling(i32Node, "I32",i32Node));
  EXPECT_TRUE(xmlbase.read<Z_I32>(i32Node, i32));
  EXPECT_EQ((Z_I32)2147483647, i32);
  EXPECT_TRUE(xmlbase.getNextSibling(i32Node, "I32",i32Node));
  EXPECT_TRUE(xmlbase.read<Z_I32>(i32Node, i32));
  EXPECT_EQ((Z_I32)2147483648, i32);

  i32Node = xmlbase.getChildNode(root, "I32ERR");
  EXPECT_TRUE(i32Node != Z_NULL);
  do{
    EXPECT_FALSE(xmlbase.read<Z_I32>(i32Node, i32)) << "value = " << i32Node->Value();
    i32Node = xmlbase.getNextSibling(i32Node, "I32ERR");
  } while(i32Node != Z_NULL);

  zsystem::xmlNode i8Node(Z_NULL);
  EXPECT_TRUE(xmlbase.getChildNode(root, "I8Attr", i8Node));
  EXPECT_TRUE(i8Node != Z_NULL);
  EXPECT_STREQ("I8Attr", i8Node->Value());
  Z_I8 i8(0);
  EXPECT_TRUE(xmlbase.readAttribute<Z_I8>(i8Node, i8, "attr"));
  EXPECT_EQ((Z_I32)1, (Z_I32)i8);

  zsystem::xmlNode pathNode(Z_NULL);
  EXPECT_TRUE(xmlbase.getChildNodeByPath(root, "Path1.Path2.Path3", pathNode));
  EXPECT_TRUE(pathNode != Z_NULL);
  EXPECT_STREQ("Path3", pathNode->Value());
  EXPECT_TRUE(xmlbase.getChildNodeByPath(root, "Path1.Path2.Path3.", pathNode));
  EXPECT_TRUE(pathNode != Z_NULL);
  EXPECT_STREQ("Path3", pathNode->Value());
  EXPECT_TRUE(xmlbase.getChildNodeByPath(root, ".Path1.Path2.Path3", pathNode));
  EXPECT_TRUE(pathNode != Z_NULL);
  EXPECT_STREQ("Path3", pathNode->Value());
  EXPECT_TRUE(xmlbase.getChildNodeByPath(root, "Path1", pathNode));
  EXPECT_TRUE(pathNode != Z_NULL);
  EXPECT_STREQ("Path1", pathNode->Value());
  EXPECT_TRUE(xmlbase.getChildNodeByPath(root, "..Path1", pathNode));
  EXPECT_TRUE(pathNode != Z_NULL);
  EXPECT_STREQ("Path1", pathNode->Value());
  EXPECT_TRUE(xmlbase.getChildNodeByPath(root, "Path1..", pathNode));
  EXPECT_TRUE(pathNode != Z_NULL);
  EXPECT_STREQ("Path1", pathNode->Value());

  pathNode = xmlbase.getChildNodeByPath(root, "Path1.Path2.Path3");
  EXPECT_TRUE(pathNode != Z_NULL);
  EXPECT_STREQ("Path3", pathNode->Value());
  pathNode = xmlbase.getChildNodeByPath(root, ".Path1.Path2.Path3.");
  EXPECT_TRUE(pathNode != Z_NULL);
  EXPECT_STREQ("Path3", pathNode->Value());
  pathNode = xmlbase.getChildNodeByPath(root, "Path1..Path2..Path3");
  EXPECT_TRUE(pathNode != Z_NULL);
  EXPECT_STREQ("Path3", pathNode->Value());
  pathNode = xmlbase.getChildNodeByPath(root, "Path1");
  EXPECT_TRUE(pathNode != Z_NULL);
  EXPECT_STREQ("Path1", pathNode->Value());
  pathNode = xmlbase.getChildNodeByPath(root, "...Path1");
  EXPECT_TRUE(pathNode != Z_NULL);
  EXPECT_STREQ("Path1", pathNode->Value());
  pathNode = xmlbase.getChildNodeByPath(root, "Path1...");
  EXPECT_TRUE(pathNode != Z_NULL);
  EXPECT_STREQ("Path1", pathNode->Value());

  EXPECT_TRUE(xmlbase.getChildNodeByPath(root, "longParent.child.longChild", pathNode));
  EXPECT_TRUE(pathNode != Z_NULL);
  EXPECT_STREQ("longChild", pathNode->Value());

  char strInt[32] = "123";
  Z_U8 u8(0);
  EXPECT_TRUE(zsystem::xmlbase::parse<Z_U8>(strInt, u8));
  EXPECT_TRUE((Z_U16)123, (Z_U16)u8);
  EXPECT_TRUE(zsystem::xmlbase::parse<Z_I8>(strInt, i8));
  EXPECT_TRUE((Z_U16)123, (Z_U16)i8);
}
#endif

#if TEST_xmlFile

TEST_F(utcase, xmlFile)
{
  EXPECT_TRUE(xmlfile.open("../../unittest/xml/test.xml"));
  zsystem::xmlNode root;
  EXPECT_TRUE(xmlfile.getRootNode(root));
  EXPECT_TRUE(root != Z_NULL);
  EXPECT_TRUE(xmlfile.save());
}

#endif


#if TEST_getOpt

TEST_F(utcase, getOpt)
{
  char argvs[16][64]={
    "c:/XXX.exe",
    "-PlayerTimeout=100",
    "-config=./config/test.xml",
    "-DumpInformation=yes",
    "-DecodeThreads=1000",
    "-ConnectionServer.SendBufferSize=20"
  };

  char* argv[16];
  Z_I32 argc(0);
  for(;argc < 16; argc++)
  {
    if (strnlen(argvs[argc], 64) == 0)
      break;
    argv[argc] = &(argvs[argc][0]);
  }
  zsystem::xmlGetOpt opt;
  ASSERT_TRUE(opt.parse(argc, argv));
  zsystem::xmlNode root(Z_NULL);
  ASSERT_TRUE(opt.getRootNode(root));
  zsystem::xmlNode node(Z_NULL);
  ASSERT_TRUE (opt.getChildNodeByPath(root, "config", node));
  std::string strFilePath;
  ASSERT_TRUE (opt.read(node, strFilePath));
  EXPECT_STREQ("./config/test.xml", strFilePath.c_str());
  Z_U16 pt(0);
  ASSERT_TRUE (opt.getChildNodeByPath(root, "PlayerTimeout", node));
  EXPECT_TRUE(opt.read(node, pt));
  EXPECT_EQ((Z_U16)100, pt);
  Z_BOOL di(Z_FALSE);
  ASSERT_TRUE (opt.getChildNodeByPath(root, "DumpInformation", node));
  EXPECT_TRUE(opt.read(node, di));
  EXPECT_TRUE(di);
  Z_I64 dt(0);
  ASSERT_TRUE (opt.getChildNodeByPath(root, "DecodeThreads", node));
  EXPECT_TRUE(opt.read(node, dt));
  EXPECT_EQ((Z_I64)1000, dt);
  Z_U64 sbs(0);
  ASSERT_TRUE (opt.getChildNode(root, "ConnectionServer.SendBufferSize", node));
  EXPECT_TRUE(opt.read(node, sbs));
  EXPECT_EQ((Z_U64)20, sbs);
}
#endif

#if TEST_xmlConfig

TEST_F(utcase, xmlConfig)
{
  zsystem::xmlConfig xml1, xml2;
  zsystem::xmlNode root;

  Z_U8 DecodeThreads(0);
  Z_U32 OperationBufferSize(0);
  Z_BOOL DumpInformation(Z_FALSE);
  Z_U64 SendBufferSize(0);
  Z_U64 PadBufferSize(0);

  EXPECT_TRUE(xml1.open("../../unittest/xml/test.xml", Z_NULL));
  EXPECT_TRUE(xml1.getRootNode(root));
  EXPECT_TRUE(root != Z_NULL);

  EXPECT_TRUE(xml1.readConfig<Z_U8>("DecodeThreads", DecodeThreads));
  EXPECT_EQ((Z_U8)1, DecodeThreads);
  EXPECT_TRUE(xml1.readConfig<Z_U32>("OperationBufferSize", OperationBufferSize));
  EXPECT_EQ((Z_U32)480000, OperationBufferSize);
  EXPECT_TRUE(xml1.readConfig<Z_BOOL>("DumpInformation", DumpInformation));
  EXPECT_FALSE(DumpInformation);
  EXPECT_TRUE(xml1.readConfig<Z_U64>("ConnectionServer.SendBufferSize", SendBufferSize));
  EXPECT_EQ((Z_U64)4192200, SendBufferSize);

  zsystem::xmlNode envNode = xml1.getChildNode(root, "Enviroment");
  EXPECT_TRUE(xml1.readConfig<Z_U64>("PadBufferSize", PadBufferSize, envNode));
  EXPECT_EQ((Z_U64)5000000, PadBufferSize);


  char argvs[16][64]={
    "c:/XXX.exe",
    "-PlayerTimeout=100",
    "-config=../../unittest/xml/test.xml",
    "-DumpInformation=yes",
    "-DecodeThreads=100",
    "-ConnectionServer.SendBufferSize=20"
  };

  char* argv[16];
  Z_I32 argc(0);
  for(;argc < 16; argc++)
  {
    if (strnlen(argvs[argc], 64) == 0)
      break;
    argv[argc] = &(argvs[argc][0]);
  }
  zsystem::xmlGetOpt opt;
  ASSERT_TRUE(opt.parse(argc, argv));
  EXPECT_TRUE(xml2.open(Z_NULL, &opt));
  EXPECT_TRUE(xml2.getRootNode(root));
  EXPECT_TRUE(root != Z_NULL);

  EXPECT_TRUE(xml2.readConfig<Z_U8>("DecodeThreads", DecodeThreads));
  EXPECT_EQ((Z_U8)100, DecodeThreads);
  EXPECT_TRUE(xml2.readConfig<Z_U32>("OperationBufferSize", OperationBufferSize));
  EXPECT_EQ((Z_U32)480000, OperationBufferSize);
  EXPECT_TRUE(xml2.readConfig<Z_BOOL>("DumpInformation", DumpInformation));
  EXPECT_TRUE(DumpInformation);
  EXPECT_TRUE(xml2.readConfig<Z_U64>("ConnectionServer.SendBufferSize", SendBufferSize));
  EXPECT_EQ((Z_U64)20, SendBufferSize);

  envNode = xml2.getChildNode(root, "Enviroment");
  EXPECT_TRUE(xml2.readConfig<Z_U64>("PadBufferSize", PadBufferSize, envNode));
  EXPECT_EQ((Z_U64)5000000, PadBufferSize);

}


#endif

#if TEST_saxParse
#include <libxml/xmlreader.h>

void saxNodeParsed(xmlTextReaderPtr reader)
{
  xmlChar *name, *value;

  name = xmlTextReaderName(reader);
  if (name == NULL)
      name = xmlStrdup(BAD_CAST "--");
  value = xmlTextReaderValue(reader);

  try
  {
    int depth = xmlTextReaderDepth(reader);
    int type = xmlTextReaderNodeType(reader);
    int isEmptyElement = xmlTextReaderIsEmptyElement(reader);
    LOG(INFO) << "Depth = " << depth << ", " <<
      "NodeType = " << type << ", " <<
      "Name = " << name << ", " <<
      "IsEmptyElement = " << (isEmptyElement?"yes":"no") << ", " <<
      "Value = " << (value!=Z_NULL?value:(const xmlChar*)"NULL") ;

    if (strncmp((const char*)name, "I8Attr", 32) == 0 && type == XML_READER_TYPE_ELEMENT)
    {
      xmlChar *attr;
      attr = xmlTextReaderGetAttribute(reader, (const xmlChar*)"attr");
      EXPECT_TRUE(Z_NULL != attr);
      if (Z_NULL != attr)
      {
        EXPECT_STREQ("1", (const char*)attr);
      }
    }
  }
  catch(...)
  {
    LOG(ERROR) << "Parse error on node[" << name << "]";
  }
  xmlFree(name);
  if (value != NULL)
    xmlFree(value);
}

TEST_F(utcase, saxParse)
{
  xmlTextReaderPtr reader;
  int ret;

  reader = xmlNewTextReaderFilename("../../unittest/xml/test.xml");
  ASSERT_TRUE(reader != NULL) << "Unable to open file";

  ret = xmlTextReaderRead(reader);
  while (ret == 1) 
  {
    saxNodeParsed(reader);
    ret = xmlTextReaderRead(reader);
  }
  xmlFreeTextReader(reader);
  ASSERT_TRUE(ret == 0) << "pailed to parse";

  int size = strnlen(utcase::testXML, 2048);
  EXPECT_GT(2048, size);
  reader = xmlReaderForMemory(utcase::testXML, size, Z_NULL, "UTF-8", 0);
  ASSERT_TRUE(reader != NULL) << "Unable to parse memory";

  ret = xmlTextReaderRead(reader);
  while (ret == 1) 
  {
    saxNodeParsed(reader);
    ret = xmlTextReaderRead(reader);
  }
  xmlFreeTextReader(reader);
  ASSERT_TRUE(ret == 0) << "pailed to parse";
}

#endif

#if TEST_objParse
#include <libxml/xmlreader.h>
#include <zsystem/core/xml/xmlbase.h>

#define XML_OBJ_BEGIN               oss << "<o _n=\"" << name << "\"";
#define XML_OBJ_PROP_BEGIN          oss << " ";
#define XML_OBJ_PROP(NAME)          oss << (#NAME"=\"") << this->NAME << "\" ";
#define XML_OBJ_PROP_END            oss << ">";

#define XML_OBJ_CHILD(CHILD, NAME)  CHILD.__toXml(oss, NAME);

#define XML_OBJ_END_NO_CHILD        oss << "/>";
#define XML_OBJ_END                 oss << "</o>";

#define XML_OBJ_NAME_MAX_LEN        32

#define XML_OBJ_SET_VALUE(TYPE, NAME)     \
  if (strncmp(name, #NAME, XML_OBJ_NAME_MAX_LEN) == 0){ zsystem::xmlbase::parse<TYPE>(value, this->NAME); return; }

#define XML_OBJ_GET_CHILD(TYPE, NAME)     \
  if (strncmp(name, #NAME, XML_OBJ_NAME_MAX_LEN) == 0){ return &(this->NAME); }

#define XML_OBJ_GET_ARRAY_CHILD(TYPE, NAME)     \
  if (strncmp(name, #NAME, XML_OBJ_NAME_MAX_LEN) == 0){ return &(this->NAME); }

class xmlObjBase{
public:
  virtual void __set(const char* name, const char* value) = 0;
  virtual xmlObjBase* __getChild(const char* name, const int index = -1) = 0;
  virtual void __toXml(std::ostream& oss, const char* name) = 0;
};

class position : public xmlObjBase{
public:
  int x;
  int y;
  virtual void __set(const char* name, const char* value)
  {
    XML_OBJ_SET_VALUE(int, x)
    XML_OBJ_SET_VALUE(int, y)
    //if (strncmp(name, "x", 32) == 0)
    //{
    //  zsystem::xmlbase::parse<int>(value, this->x);
    //}
    //else if(strncmp(name, "y", 32) == 0)
    //{
    //  zsystem::xmlbase::parse<int>(value, this->y);
    //}
  }
  virtual xmlObjBase* __getChild(const char* name, const int index = -1)
  {
    return Z_NULL;
  }
  virtual void __toXml(std::ostream& oss, const char* name)
  {
    XML_OBJ_BEGIN
    XML_OBJ_PROP_BEGIN
    XML_OBJ_PROP(x)
    XML_OBJ_PROP(y)
    XML_OBJ_PROP_END
    XML_OBJ_END;
  }
};

class army : public xmlObjBase{
public:
  position pos;
  Z_U32 state;
  char name[24];
  virtual void __set(const char* name, const char* value)
  {
    if (strncmp(name, "state", 32) == 0)
    {
      zsystem::xmlbase::parse<Z_U32>(value, this->state);
    }
    else if(strncmp(name, "name", 32) == 0)
    {
      LOG(INFO) << "name: " << value;
      strncpy(this->name, value, 24);
    }
  }
  virtual xmlObjBase* __getChild(const char* name, const int index = -1)
  {
    if (strncmp(name, "pos", 32) == 0)
    {
      return &(this->pos);
    }
    return Z_NULL;
  }
  virtual void __toXml(std::ostream& oss, const char* name)
  {
    XML_OBJ_BEGIN
    XML_OBJ_PROP_BEGIN
    XML_OBJ_PROP_END
    XML_OBJ_CHILD(pos, "pos");
    XML_OBJ_END;
  }
};

class map : public xmlObjBase{
public:
  army armys[10];
  unsigned int _armysNumber;
  int mapID;
  char name[24];
  map():_armysNumber(0){};
  virtual void __set(const char* name, const char* value)
  {
    if (strncmp(name, "mapID", 32) == 0)
    {
      this->mapID = atoi(value);
    }
    else if(strncmp(name, "name", 32) == 0)
    {
      strncpy(this->name, value, 24);
    }
  }
  virtual xmlObjBase* __getChild(const char* name, const int index = -1)
  {
    if (strncmp(name, "armys", 32) == 0)
    {
      if ( -1 == index )
      {
        if (_armysNumber < 10)
        {
          return &(this->armys[_armysNumber++]);
        }
        else
        {
          return Z_NULL;
        }
      }
      else
      {
          return (index < _armysNumber ? &(this->armys[index]) : Z_NULL);
      }
    }
    return Z_NULL;
  }
  virtual void __toXml(std::ostream& oss, const char* name)
  {
    XML_OBJ_BEGIN
    XML_OBJ_PROP_BEGIN
    XML_OBJ_PROP(mapID)
    XML_OBJ_PROP(name)
    XML_OBJ_PROP_END

    for(int i = 0; i < _armysNumber; i++)
    {
      XML_OBJ_CHILD(armys[i], "armys");
    }
    XML_OBJ_END;
  }
};

#include <stack>

void objNodeParsed(xmlTextReaderPtr reader, std::stack<xmlObjBase*> & objStack)
{
  xmlChar *name, *value;

  name = xmlTextReaderName(reader);
  if (name == NULL)
    return;

  xmlObjBase* obj = objStack.top();
  int depth = xmlTextReaderDepth(reader);
  int type = xmlTextReaderNodeType(reader);
  switch(type)
  {
  case XML_READER_TYPE_ELEMENT:
    {
      if(strncmp((const char*)name, "o", 1) == 0)
      {
        xmlObjBase* childObj(Z_NULL);
        if (depth == 0)
        {
          // Root
          if (objStack.size() != 1)
          {
            LOG(ERROR) << "parse object failed! root duplicated";
          }
          childObj = obj;
        }
        else
        {
          if (obj != Z_NULL)
          {
            xmlChar* nameObj = xmlTextReaderGetAttribute(reader, (const xmlChar*)"_n");
            if (nameObj != Z_NULL)
            {
              childObj = obj->__getChild((const char*)nameObj);
              xmlFree(nameObj);
            }
          }
          if (xmlTextReaderIsEmptyElement(reader) == 0)
            objStack.push(childObj);
        }

        if (childObj != Z_NULL)
        {
          int attrCount = xmlTextReaderAttributeCount(reader);
          for (int i = 0; i < attrCount; i++)
          {
            if( 0 == xmlTextReaderMoveToAttributeNo(reader, i))
              break;

            xmlChar* attrName = xmlTextReaderLocalName(reader);
            if (attrName != Z_NULL)
            {
              xmlChar* attrValue = xmlTextReaderValue(reader);
              if (attrValue != Z_NULL)
              {
                childObj->__set((const char*)attrName, (const char*)attrValue);
                xmlFree(attrValue);
              }
              xmlFree(attrName);
            }
          }
        }
      }
      else
      {
        objStack.push(Z_NULL);
      }
    }
    break;
  case XML_READER_TYPE_END_ELEMENT:
    objStack.pop();
    break;
  }

  xmlFree(name);
}

TEST_F(utcase, objParse)
{
  xmlTextReaderPtr reader;
  int ret;

  reader = xmlNewTextReaderFilename("../../unittest/xml/obj.xml");
  ASSERT_TRUE(reader != NULL) << "Unable to open file";

  ret = xmlTextReaderRead(reader);
  map m;
  
  std::stack<xmlObjBase*> objStack;
  objStack.push(&m);
  while (ret == 1) 
  {
    objNodeParsed(reader, objStack);
    ret = xmlTextReaderRead(reader);
  }
  xmlFreeTextReader(reader);
  ASSERT_TRUE(ret == 0) << "failed to parse";

  std::ostringstream oss;
  m.__toXml(oss, "map");
  std::string str = oss.str();
  LOG(INFO) << "__toXml() = \n" << str;

  xmlTextReaderPtr reader2;
  int len = str.length();
  reader2 = xmlReaderForMemory(str.c_str(), len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
  ASSERT_TRUE(reader2 != NULL) << "Unable to parse memory data";

  ret = xmlTextReaderRead(reader2);
  ASSERT_TRUE(ret == 1) << "failed to read";

  map m2;
  std::stack<xmlObjBase*> objStack2;
  objStack2.push(&m2);
  while (ret == 1) 
  {
    objNodeParsed(reader2, objStack2);
    ret = xmlTextReaderRead(reader2);
  }
  xmlFreeTextReader(reader2);
  ASSERT_TRUE(ret == 0) << "failed to parse from memory";
}

#endif

int main(int argc, char **argv) 
{
  google::InitGoogleLogging(argv[0]);
#ifdef __WIN32__
    google::SetLogDestination(INFO, "..\\..\\..\\logs\\INFO_");
    google::SetLogDestination(WARNING, "..\\..\\..\\logs\\WARNING_");
    google::SetLogDestination(ERROR, "..\\..\\..\\logs\\ERROR_");
#endif
#ifdef __LINUX__
    google::SetLogDestination(INFO, "/tmp/INFO_");
    google::SetLogDestination(WARNING, "/tmp/WARNING_");
    google::SetLogDestination(ERROR, "/tmp/ERROR_");
#endif
  ::testing::InitGoogleTest(&argc, argv);


  int r = RUN_ALL_TESTS();
#ifdef __WIN32__
  getchar();
#endif

  google::ShutdownGoogleLogging();

  return r;
}
